package drds.server.config.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import drds.server.util.StringUtil;

/**
 * 
 */
public class ParameterMapping {
	private static final Logger LOGGER = LoggerFactory.getLogger(ParameterMapping.class);
	private static final Map<Class<?>, PropertyDescriptor[]> propertyDescriptorsMap = new HashMap<Class<?>, PropertyDescriptor[]>();

	/**
	 * 将property键值对赋值组装到object中
	 * 
	 * @param object
	 *            目标反射对象
	 * @param parameterMap
	 *            property的键值对
	 */
	public static void mapping(Object object, Map<String, ? extends Object> parameterMap) throws IllegalAccessException, InvocationTargetException {
		// 获取用于导出clazz这个JavaBean的所有属性的PropertyDescriptor
		PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(object.getClass());
		int length = propertyDescriptors.length;
		for (int i = 0; i < length; i++) {
			PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
			Object parameter = parameterMap.get(propertyDescriptor.getName());
			Object value = parameter;
			Class<?> $class = propertyDescriptor.getPropertyType();
			// 类型转换
			if (parameter instanceof String) {
				String string = (String) parameter;
				if (!StringUtil.isEmpty(string)) {
					string = ConfigUtil.filter(string);
				}
				if (isPrimitiveType($class)) {
					value = convert($class, string);
				}
			} else if (parameter instanceof BeanConfig) {
				value = createBean((BeanConfig) parameter);
			} else if (parameter instanceof BeanConfig[]) {
				List<Object> list = new ArrayList<Object>();
				for (BeanConfig beanconfig : (BeanConfig[]) parameter) {
					list.add(createBean(beanconfig));
				}
				value = list.toArray();
			}
			// 赋值
			if ($class != null && value != null) {
				Method method = propertyDescriptor.getWriteMethod();
				if (method != null) {
					method.invoke(object, new Object[] { value });
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static Object createBean(BeanConfig beanConfig) throws IllegalAccessException, InvocationTargetException {
		Object bean = beanConfig.create(true);
		if (bean instanceof Map) {
			Map<String, Object> map = (Map<String, Object>) bean;
			for (Map.Entry<String, Object> entry : beanConfig.getParams().entrySet()) {
				String key = entry.getKey();
				Object value = entry.getValue();
				if (value instanceof BeanConfig) {
					BeanConfig mapBeanConfig = (BeanConfig) entry.getValue();
					value = mapBeanConfig.create(true);
					mapping(value, mapBeanConfig.getParams());
				}
				map.put(key, value);
			}
		} else if (bean instanceof List) {
		} else {
			mapping(bean, beanConfig.getParams());
		}
		return bean;
	}

	/**
	 * 用于导出clazz这个JavaBean的所有属性的PropertyDescriptor
	 * 
	 * @param $class
	 * @return
	 */
	private static PropertyDescriptor[] getPropertyDescriptors(Class<?> $class) {
		// 该clazz是否第一次加载
		if (propertyDescriptorsMap.containsKey($class)) {
			return propertyDescriptorsMap.get($class);
		} else {

			BeanInfo beanInfo = null;
			try {
				beanInfo = Introspector.getBeanInfo($class);
			} catch (IntrospectionException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			List<PropertyDescriptor> propertyDescriptorList = new ArrayList<PropertyDescriptor>();
			// 加载每一个类型不为空的property
			int length = propertyDescriptors.length;
			for (int i = 0; i < length; i++) {
				if (null != propertyDescriptors[i].getPropertyType()) {
					propertyDescriptorList.add(propertyDescriptors[i]);
				}
			}
			PropertyDescriptor[] $propertyDescriptors = new PropertyDescriptor[propertyDescriptorList.size()];
			propertyDescriptorList.toArray($propertyDescriptors);
			propertyDescriptorsMap.put($class, $propertyDescriptors);
			return $propertyDescriptors;
		}

	}

	private static Object convert(Class<?> $class, String string) {
		Method method = null;
		Object value = null;
		if ($class.equals(String.class)) {
			value = string;
		} else if ($class.equals(Boolean.TYPE)) {
			value = Boolean.valueOf(string);
		} else if ($class.equals(Byte.TYPE)) {
			value = Byte.valueOf(string);
		} else if ($class.equals(Short.TYPE)) {
			value = Short.valueOf(string);
		} else if ($class.equals(Integer.TYPE)) {
			value = Integer.valueOf(string);
		} else if ($class.equals(Long.TYPE)) {
			value = Long.valueOf(string);
		} else if ($class.equals(Double.TYPE)) {
			value = Double.valueOf(string);
		} else if ($class.equals(Float.TYPE)) {
			value = Float.valueOf(string);
		} else if (($class.equals(Boolean.class)) || ($class.equals(Byte.class)) || ($class.equals(Short.class)) || ($class.equals(Integer.class)) || ($class.equals(Long.class)) || ($class.equals(Float.class)) || ($class.equals(Double.class))) {
			try {
				method = $class.getMethod("valueOf", new Class[] { String.class });
				value = method.invoke(null, new Object[] { string });
			} catch (Exception t) {
				LOGGER.error("valueofError", t);
				value = null;
			}
		} else if ($class.equals(Class.class)) {
			try {
				value = Class.forName(string);
			} catch (ClassNotFoundException e) {
				throw new ConfigException(e);
			}
		} else {
			value = null;
		}
		return (value);
	}

	private static boolean isPrimitiveType(Class<?> $class) {
		if ($class.equals(String.class) || $class.equals(Boolean.TYPE) || $class.equals(Byte.TYPE) || $class.equals(Short.TYPE) || $class.equals(Integer.TYPE) || $class.equals(Long.TYPE) || $class.equals(Double.TYPE) || $class.equals(Float.TYPE) || $class.equals(Boolean.class) || $class.equals(Byte.class) || $class.equals(Short.class) || $class.equals(Integer.class) || $class.equals(Long.class)
				|| $class.equals(Float.class) || $class.equals(Double.class) || $class.equals(Class.class)) {
			return true;
		} else {
			return false;
		}
	}

}